home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gscoord.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  14.0 KB  |  541 lines

  1. /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gscoord.c,v 1.5 2000/09/19 19:00:26 lpd Exp $ */
  20. /* Coordinate system operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsccode.h"        /* for gxfont.h */
  25. #include "gxfarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"
  28. #include "gxfont.h"        /* for char_tm */
  29. #include "gxpath.h"        /* for gx_path_translate */
  30. #include "gzstate.h"
  31. #include "gxcoord.h"        /* requires gsmatrix, gsstate */
  32. #include "gxdevice.h"
  33.  
  34. /* Choose whether to enable the rounding code in update_ctm. */
  35. #define ROUND_CTM_FIXED 1
  36.  
  37. /* Forward declarations */
  38. #ifdef DEBUG
  39. #define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
  40. private void trace_matrix_fixed(P1(const gs_matrix_fixed *));
  41. private void trace_matrix(P1(const gs_matrix *));
  42.  
  43. #endif
  44.  
  45. /* Macro for ensuring ctm_inverse is valid */
  46. #ifdef DEBUG
  47. #  define print_inverse(pgs)\
  48.      if ( gs_debug_c('x') )\
  49.        dlprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
  50. #else
  51. #  define print_inverse(pgs) DO_NOTHING
  52. #endif
  53. #define ensure_inverse_valid(pgs)\
  54.     if ( !pgs->ctm_inverse_valid )\
  55.        {    int code = ctm_set_inverse(pgs);\
  56.         if ( code < 0 ) return code;\
  57.        }
  58.  
  59. private int
  60. ctm_set_inverse(gs_state * pgs)
  61. {
  62.     int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
  63.  
  64.     print_inverse(pgs);
  65.     if (code < 0)
  66.     return code;
  67.     pgs->ctm_inverse_valid = true;
  68.     return 0;
  69. }
  70.  
  71. /* Machinery for updating fixed version of ctm. */
  72. /*
  73.  * We (conditionally) adjust the floating point translation
  74.  * so that it exactly matches the (rounded) fixed translation.
  75.  * This avoids certain unpleasant rounding anomalies, such as
  76.  * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
  77.  * not returning 0 0.
  78.  */
  79. #if ROUND_CTM_FIXED
  80. #  define update_t_fixed(mat, t, t_fixed, v)\
  81.     (set_float2fixed_vars((mat).t_fixed, v),\
  82.      set_fixed2float_var((mat).t, (mat).t_fixed))
  83. #else /* !ROUND_CTM_FIXED */
  84. #  define update_t_fixed(mat, t, t_fixed, v)\
  85.     ((mat).t = (v),\
  86.      set_float2fixed_vars((mat).t_fixed, (mat).t))
  87. #endif /* (!)ROUND_CTM_FIXED */
  88. #define f_fits_in_fixed(f) f_fits_in_bits(f, fixed_int_bits)
  89. #define update_matrix_fixed(mat, xt, yt)\
  90.   ((mat).txy_fixed_valid = (f_fits_in_fixed(xt) && f_fits_in_fixed(yt) ?\
  91.                 (update_t_fixed(mat, tx, tx_fixed, xt),\
  92.                  update_t_fixed(mat, ty, ty_fixed, yt), true) :\
  93.                 ((mat).tx = (xt), (mat).ty = (yt), false)))
  94. #define update_ctm(pgs, xt, yt)\
  95.   (pgs->ctm_inverse_valid = false,\
  96.    pgs->char_tm_valid = false,\
  97.    update_matrix_fixed(pgs->ctm, xt, yt))
  98.  
  99. /* ------ Coordinate system definition ------ */
  100.  
  101. int
  102. gs_initmatrix(gs_state * pgs)
  103. {
  104.     gs_matrix imat;
  105.  
  106.     gs_defaultmatrix(pgs, &imat);
  107.     update_ctm(pgs, imat.tx, imat.ty);
  108.     set_ctm_only(pgs, imat);
  109. #ifdef DEBUG
  110.     if (gs_debug_c('x'))
  111.     dlprintf("[x]initmatrix:\n"), trace_ctm(pgs);
  112. #endif
  113.     return 0;
  114. }
  115.  
  116. int
  117. gs_defaultmatrix(const gs_state * pgs, gs_matrix * pmat)
  118. {
  119.     gx_device *dev;
  120.  
  121.     if (pgs->ctm_default_set) {    /* set after Install */
  122.     *pmat = pgs->ctm_default;
  123.     return 1;
  124.     }
  125.     dev = gs_currentdevice_inline(pgs);
  126.     gs_deviceinitialmatrix(dev, pmat);
  127.     /* Add in the translation for the Margins. */
  128.     pmat->tx += dev->Margins[0] *
  129.     dev->HWResolution[0] / dev->MarginsHWResolution[0];
  130.     pmat->ty += dev->Margins[1] *
  131.     dev->HWResolution[1] / dev->MarginsHWResolution[1];
  132.     return 0;
  133. }
  134.  
  135. int
  136. gs_setdefaultmatrix(gs_state * pgs, const gs_matrix * pmat)
  137. {
  138.     if (pmat == NULL)
  139.     pgs->ctm_default_set = false;
  140.     else {
  141.     pgs->ctm_default = *pmat;
  142.     pgs->ctm_default_set = true;
  143.     }
  144.     return 0;
  145. }
  146.  
  147. int
  148. gs_currentmatrix(const gs_state * pgs, gs_matrix * pmat)
  149. {
  150.     *pmat = ctm_only(pgs);
  151.     return 0;
  152. }
  153.  
  154. /* Set the current transformation matrix for rendering text. */
  155. /* Note that this may be based on a font other than the current font. */
  156. int
  157. gs_setcharmatrix(gs_state * pgs, const gs_matrix * pmat)
  158. {
  159.     gs_matrix cmat;
  160.     int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
  161.  
  162.     if (code < 0)
  163.     return code;
  164.     update_matrix_fixed(pgs->char_tm, cmat.tx, cmat.ty);
  165.     char_tm_only(pgs) = cmat;
  166. #ifdef DEBUG
  167.     if (gs_debug_c('x'))
  168.     dlprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
  169. #endif
  170.     pgs->char_tm_valid = true;
  171.     return 0;
  172. }
  173.  
  174. /* Read (after possibly computing) the current transformation matrix */
  175. /* for rendering text.  If force=true, update char_tm if it is invalid; */
  176. /* if force=false, don't update char_tm, and return an error code. */
  177. int
  178. gs_currentcharmatrix(gs_state * pgs, gs_matrix * ptm, bool force)
  179. {
  180.     if (!pgs->char_tm_valid) {
  181.     int code;
  182.  
  183.     if (!force)
  184.         return_error(gs_error_undefinedresult);
  185.     code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
  186.     if (code < 0)
  187.         return code;
  188.     }
  189.     if (ptm != NULL)
  190.     *ptm = char_tm_only(pgs);
  191.     return 0;
  192. }
  193.  
  194. int
  195. gs_setmatrix(gs_state * pgs, const gs_matrix * pmat)
  196. {
  197.     update_ctm(pgs, pmat->tx, pmat->ty);
  198.     set_ctm_only(pgs, *pmat);
  199. #ifdef DEBUG
  200.     if (gs_debug_c('x'))
  201.     dlprintf("[x]setmatrix:\n"), trace_ctm(pgs);
  202. #endif
  203.     return 0;
  204. }
  205.  
  206. int
  207. gs_imager_setmatrix(gs_imager_state * pis, const gs_matrix * pmat)
  208. {
  209.     update_matrix_fixed(pis->ctm, pmat->tx, pmat->ty);
  210.     set_ctm_only(pis, *pmat);
  211. #ifdef DEBUG
  212.     if (gs_debug_c('x'))
  213.     dlprintf("[x]imager_setmatrix:\n"), trace_ctm(pis);
  214. #endif
  215.     return 0;
  216. }
  217.  
  218. int
  219. gs_settocharmatrix(gs_state * pgs)
  220. {
  221.     if (pgs->char_tm_valid) {
  222.     pgs->ctm = pgs->char_tm;
  223.     pgs->ctm_inverse_valid = false;
  224.     return 0;
  225.     } else
  226.     return_error(gs_error_undefinedresult);
  227. }
  228.  
  229. int
  230. gs_translate(gs_state * pgs, floatp dx, floatp dy)
  231. {
  232.     gs_point pt;
  233.     int code;
  234.  
  235.     if ((code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0)
  236.     return code;
  237.     pt.x += pgs->ctm.tx;
  238.     pt.y += pgs->ctm.ty;
  239.     update_ctm(pgs, pt.x, pt.y);
  240. #ifdef DEBUG
  241.     if (gs_debug_c('x'))
  242.     dlprintf4("[x]translate: %f %f -> %f %f\n",
  243.           dx, dy, pt.x, pt.y),
  244.         trace_ctm(pgs);
  245. #endif
  246.     return 0;
  247. }
  248.  
  249. int
  250. gs_scale(gs_state * pgs, floatp sx, floatp sy)
  251. {
  252.     pgs->ctm.xx *= sx;
  253.     pgs->ctm.xy *= sx;
  254.     pgs->ctm.yx *= sy;
  255.     pgs->ctm.yy *= sy;
  256.     pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
  257. #ifdef DEBUG
  258.     if (gs_debug_c('x'))
  259.     dlprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
  260. #endif
  261.     return 0;
  262. }
  263.  
  264. int
  265. gs_rotate(gs_state * pgs, floatp ang)
  266. {
  267.     int code = gs_matrix_rotate(&ctm_only(pgs), ang,
  268.                 &ctm_only_writable(pgs));
  269.  
  270.     pgs->ctm_inverse_valid = false, pgs->char_tm_valid = false;
  271. #ifdef DEBUG
  272.     if (gs_debug_c('x'))
  273.     dlprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
  274. #endif
  275.     return code;
  276. }
  277.  
  278. int
  279. gs_concat(gs_state * pgs, const gs_matrix * pmat)
  280. {
  281.     gs_matrix cmat;
  282.     int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &cmat);
  283.  
  284.     if (code < 0)
  285.     return code;
  286.     update_ctm(pgs, cmat.tx, cmat.ty);
  287.     set_ctm_only(pgs, cmat);
  288. #ifdef DEBUG
  289.     if (gs_debug_c('x'))
  290.     dlprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
  291. #endif
  292.     return code;
  293. }
  294.  
  295. /* ------ Coordinate transformation ------ */
  296.  
  297. #define is_skewed(pmat) (!(is_xxyy(pmat) || is_xyyx(pmat)))
  298.  
  299. int
  300. gs_transform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
  301. {
  302.     return gs_point_transform(x, y, &ctm_only(pgs), pt);
  303. }
  304.  
  305. int
  306. gs_dtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
  307. {
  308.     return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
  309. }
  310.  
  311. int
  312. gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt)
  313. {                /* If the matrix isn't skewed, we get more accurate results */
  314.     /* by using transform_inverse than by using the inverse matrix. */
  315.     if (!is_skewed(&pgs->ctm)) {
  316.     return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
  317.     } else {
  318.     ensure_inverse_valid(pgs);
  319.     return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
  320.     }
  321. }
  322.  
  323. int
  324. gs_idtransform(gs_state * pgs, floatp dx, floatp dy, gs_point * pt)
  325. {                /* If the matrix isn't skewed, we get more accurate results */
  326.     /* by using transform_inverse than by using the inverse matrix. */
  327.     if (!is_skewed(&pgs->ctm)) {
  328.     return gs_distance_transform_inverse(dx, dy,
  329.                          &ctm_only(pgs), pt);
  330.     } else {
  331.     ensure_inverse_valid(pgs);
  332.     return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
  333.     }
  334. }
  335.  
  336. int
  337. gs_imager_idtransform(const gs_imager_state * pis, floatp dx, floatp dy,
  338.               gs_point * pt)
  339. {
  340.     return gs_distance_transform_inverse(dx, dy, &ctm_only(pis), pt);
  341. }
  342.  
  343. /* ------ For internal use only ------ */
  344.  
  345. /* Set the translation to a fixed value, and translate any existing path. */
  346. /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
  347. int
  348. gx_translate_to_fixed(register gs_state * pgs, fixed px, fixed py)
  349. {
  350.     double fpx = fixed2float(px);
  351.     double fdx = fpx - pgs->ctm.tx;
  352.     double fpy = fixed2float(py);
  353.     double fdy = fpy - pgs->ctm.ty;
  354.     fixed dx, dy;
  355.     int code;
  356.  
  357.     if (pgs->ctm.txy_fixed_valid) {
  358.     dx = float2fixed(fdx);
  359.     dy = float2fixed(fdy);
  360.     code = gx_path_translate(pgs->path, dx, dy);
  361.     if (code < 0)
  362.         return code;
  363.     if (pgs->char_tm_valid && pgs->char_tm.txy_fixed_valid)
  364.         pgs->char_tm.tx_fixed += dx,
  365.         pgs->char_tm.ty_fixed += dy;
  366.     } else {
  367.     if (!gx_path_is_null(pgs->path))
  368.         return_error(gs_error_limitcheck);
  369.     }
  370.     pgs->ctm.tx = fpx;
  371.     pgs->ctm.tx_fixed = px;
  372.     pgs->ctm.ty = fpy;
  373.     pgs->ctm.ty_fixed = py;
  374.     pgs->ctm.txy_fixed_valid = true;
  375.     pgs->ctm_inverse_valid = false;
  376.     if (pgs->char_tm_valid) {    /* Update char_tm now, leaving it valid. */
  377.     pgs->char_tm.tx += fdx;
  378.     pgs->char_tm.ty += fdy;
  379.     }
  380. #ifdef DEBUG
  381.     if (gs_debug_c('x')) {
  382.     dlprintf2("[x]translate_to_fixed %g, %g:\n",
  383.           fixed2float(px), fixed2float(py));
  384.     trace_ctm(pgs);
  385.     dlprintf("[x]   char_tm:\n");
  386.     trace_matrix_fixed(&pgs->char_tm);
  387.     }
  388. #endif
  389.     return 0;
  390. }
  391.  
  392. /* Scale the CTM and character matrix for oversampling. */
  393. int
  394. gx_scale_char_matrix(register gs_state * pgs, int sx, int sy)
  395. {
  396. #define scale_cxy(s, vx, vy)\
  397.   if ( s != 1 )\
  398.    {    pgs->ctm.vx *= s;\
  399.     pgs->ctm.vy *= s;\
  400.     pgs->ctm_inverse_valid = false;\
  401.     if ( pgs->char_tm_valid )\
  402.     {    pgs->char_tm.vx *= s;\
  403.         pgs->char_tm.vy *= s;\
  404.     }\
  405.    }
  406.     scale_cxy(sx, xx, yx);
  407.     scale_cxy(sy, xy, yy);
  408. #undef scale_cxy
  409.     if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
  410.     return 0;
  411. }
  412.  
  413. /* Compute the coefficients for fast fixed-point distance transformations */
  414. /* from a transformation matrix. */
  415. /* We should cache the coefficients with the ctm.... */
  416. int
  417. gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc,
  418.              int max_bits)
  419. {
  420.     gs_matrix ctm;
  421.     int scale = -10000;
  422.     int expt, shift;
  423.  
  424.     ctm = *pmat;
  425.     pfc->skewed = 0;
  426.     if (!is_fzero(ctm.xx)) {
  427.     discard(frexp(ctm.xx, &scale));
  428.     }
  429.     if (!is_fzero(ctm.xy)) {
  430.     discard(frexp(ctm.xy, &expt));
  431.     if (expt > scale)
  432.         scale = expt;
  433.     pfc->skewed = 1;
  434.     }
  435.     if (!is_fzero(ctm.yx)) {
  436.     discard(frexp(ctm.yx, &expt));
  437.     if (expt > scale)
  438.         scale = expt;
  439.     pfc->skewed = 1;
  440.     }
  441.     if (!is_fzero(ctm.yy)) {
  442.     discard(frexp(ctm.yy, &expt));
  443.     if (expt > scale)
  444.         scale = expt;
  445.     }
  446.     /*
  447.      * There are two multiplications in fixed_coeff_mult: one involves a
  448.      * factor that may have max_bits significant bits, the other may have
  449.      * fixed_fraction_bits (_fixed_shift) bits.  Ensure that neither one
  450.      * will overflow.
  451.      */
  452.     if (max_bits < fixed_fraction_bits)
  453.     max_bits = fixed_fraction_bits;
  454.     scale = sizeof(long) * 8 - 1 - max_bits - scale;
  455.  
  456.     shift = scale - _fixed_shift;
  457.     if (shift > 0) {
  458.     pfc->shift = shift;
  459.     pfc->round = (fixed) 1 << (shift - 1);
  460.     } else {
  461.     pfc->shift = 0;
  462.     pfc->round = 0;
  463.     scale -= shift;
  464.     }
  465. #define SET_C(c)\
  466.   if ( is_fzero(ctm.c) ) pfc->c = 0;\
  467.   else pfc->c = (long)ldexp(ctm.c, scale)
  468.     SET_C(xx);
  469.     SET_C(xy);
  470.     SET_C(yx);
  471.     SET_C(yy);
  472. #undef SET_C
  473. #ifdef DEBUG
  474.     if (gs_debug_c('x')) {
  475.     dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
  476.           ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
  477.     dlprintf6("   scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
  478.           scale, pfc->xx, pfc->xy, pfc->yx, pfc->yy,
  479.           pfc->shift);
  480.     }
  481. #endif
  482.     pfc->max_bits = max_bits;
  483.     return 0;
  484. }
  485.  
  486. /*
  487.  * Handle the case of a large value or a value with a fraction part.
  488.  * See gxmatrix.h for more details.
  489.  */
  490. fixed
  491. fixed_coeff_mult(fixed value, long coeff, const fixed_coeff *pfc, int maxb)
  492. {
  493.     int shift = pfc->shift;
  494.  
  495.     /*
  496.      * Test if the value is too large for simple long math.
  497.      */
  498.     if ((value + (fixed_1 << (maxb - 1))) & (-fixed_1 << maxb)) {
  499.     /* The second argument of fixed_mult_quo must be non-negative. */
  500.     return
  501.         (coeff < 0 ?
  502.          -fixed_mult_quo(value, -coeff, fixed_1 << shift) :
  503.          fixed_mult_quo(value, coeff, fixed_1 << shift));
  504.     } else {
  505.     /*
  506.      * The construction above guarantees that the multiplications
  507.      * won't overflow the capacity of an int.
  508.      */
  509.         return (fixed)
  510.         arith_rshift(fixed2int_var(value) * coeff
  511.              + fixed2int(fixed_fraction(value) * coeff)
  512.              + pfc->round, shift);
  513.     }
  514. }
  515.  
  516. /* ------ Debugging printout ------ */
  517.  
  518. #ifdef DEBUG
  519.  
  520. /* Print a matrix */
  521. private void
  522. trace_matrix_fixed(const gs_matrix_fixed * pmat)
  523. {
  524.     trace_matrix((const gs_matrix *)pmat);
  525.     if (pmat->txy_fixed_valid) {
  526.     dprintf2("\t\tt_fixed: [%6g %6g]\n",
  527.          fixed2float(pmat->tx_fixed),
  528.          fixed2float(pmat->ty_fixed));
  529.     } else {
  530.     dputs("\t\tt_fixed not valid\n");
  531.     }
  532. }
  533. private void
  534. trace_matrix(register const gs_matrix * pmat)
  535. {
  536.     dlprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
  537.           pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  538. }
  539.  
  540. #endif
  541.